"use client" import * as React from 'react' import { useRouter } from 'next/navigation' import { CheckCircle2, FileText, Inbox, TriangleAlert } from 'lucide-react' import { Button } from '@open-mercato/ui/primitives/button' import { StatusBadge } from '@open-mercato/ui/primitives/status-badge' import { apiCall } from '@open-mercato/ui/backend/utils/apiCall' import { useT } from '@open-mercato/shared/lib/i18n/context' import { DashCard, NoticeBanner } from './workspacePrimitives' import { runVolumeByDay, type AgentMetrics, type WorkspaceTab } from './workspaceShared' type EvalSection = 'assertions' | 'cases' | 'runs' type OverviewTabProps = { agentId: string metrics: AgentMetrics runs: Array> active: boolean onNavigate: (tab: WorkspaceTab, section?: EvalSection) => void } type AttentionState = { draftCases: number | null lastFailedRun: { id: string; passScore: number | null } | null loaded: boolean } function asNumber(value: unknown): number | null { if (typeof value === 'number' && Number.isFinite(value)) return value if (typeof value === 'string' && value.trim() !== '' && Number.isFinite(Number(value))) return Number(value) return null } function asString(value: unknown): string | null { return typeof value === 'string' ? value : null } export function OverviewTab({ agentId, metrics, runs, active, onNavigate }: OverviewTabProps) { const t = useT() const router = useRouter() const [attention, setAttention] = React.useState({ draftCases: null, lastFailedRun: null, loaded: false }) React.useEffect(() => { if (!active || !agentId) return let cancelled = false async function load() { const id = encodeURIComponent(agentId) const [casesCall, runsCall] = await Promise.all([ apiCall<{ total?: number; items?: unknown[] }>( `/api/agent_orchestrator/eval-cases?agentDefinitionId=${id}&status=draft&pageSize=1`, undefined, { fallback: { total: 0, items: [] } }, ), apiCall<{ items?: Array> }>( `/api/agent_orchestrator/eval-runs?agentDefinitionId=${id}&pageSize=10`, undefined, { fallback: { items: [] } }, ), ]) if (cancelled) return const draftCases = casesCall.ok ? asNumber(casesCall.result?.total) ?? (Array.isArray(casesCall.result?.items) ? casesCall.result.items.length : 0) : null let lastFailedRun: AttentionState['lastFailedRun'] = null if (runsCall.ok && Array.isArray(runsCall.result?.items)) { const failed = runsCall.result.items.find((item) => { const outcome = asString(item.outcome) return outcome === 'failed' || outcome === 'advisory' }) if (failed) { const id2 = asString(failed.id) if (id2) lastFailedRun = { id: id2, passScore: asNumber(failed.pass_score ?? failed.passScore) } } } setAttention({ draftCases, lastFailedRun, loaded: true }) } load() return () => { cancelled = true } }, [active, agentId]) const overridePct = metrics.overrideRate == null ? null : Math.round(metrics.overrideRate * 100) const overrideGate = overridePct != null && overridePct > 30 const items: React.ReactNode[] = [] const draftCases = attention.draftCases ?? 0 if (draftCases > 0) { items.push( onNavigate('evaluation', 'cases')} />, ) } if (metrics.pending > 0) { items.push( router.push('/backend/caseload')} />, ) } if (attention.lastFailedRun) { items.push( onNavigate('evaluation', 'runs')} />, ) } const spark = runVolumeByDay(runs, 14, Date.now()) const sparkMax = Math.max(1, ...spark) return (
{overrideGate ? ( {t('agent_orchestrator.agentDetail.autonomy.gateWarning', 'Override {pct}% is above the 30% gate — consider Gated.', { pct: overridePct })} ) : null} {metrics.runCount === 0 ? (

{t('agent_orchestrator.agentDetail.recent.empty', 'No runs yet for this agent.')}

) : (
{spark.map((count, index) => (
= spark.length - 4 ? 'bg-primary/70' : 'bg-primary/25'}`} style={{ height: `${Math.max(4, (count / sparkMax) * 100)}%` }} title={String(count)} /> ))}
)}
0 ? {String(items.length)} : null} > {!attention.loaded ? (

{t('agent_orchestrator.agentDetail.attention.loading', 'Checking…')}

) : items.length === 0 ? (
{t('agent_orchestrator.agentDetail.attention.clear', 'Nothing needs you right now.')}
) : (
{items}
)}
) } function AttentionRow({ tone, icon: Icon, title, body, actionLabel, onAction, }: { tone: 'warning' | 'info' | 'error' icon: React.ComponentType<{ className?: string }> title: string body: string actionLabel: string onAction: () => void }) { const toneClass = tone === 'error' ? 'bg-status-error-bg text-status-error-icon' : tone === 'warning' ? 'bg-status-warning-bg text-status-warning-icon' : 'bg-status-info-bg text-status-info-icon' return (

{title}

{body}

) }